package com.king.platform.redis;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class RedisUtils {
  @Autowired
  RedisTemplate<String, Object> redisTemplate;

  @Autowired
  StringRedisTemplate stringRedisTemplate;


  /**
   * <p>todo redis string oprators</p>
   *  @param: key
   *  @param: value
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 22:26
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void set(String key, Object value) {
    try {
      redisTemplate.opsForValue().set(key, value);
    } catch (Exception e) {
      log.error("redis set error e = {}", e.getMessage());
    }
  }

  public void set(String key, Object value, Long millis) {
    try {
      redisTemplate.opsForValue().set(key, value);
      if (millis > 0) {
        redisTemplate.expire(key, millis, TimeUnit.MILLISECONDS);
      }
    } catch (Exception e) {
      log.error("redis set error e = {}", e.getMessage());
    }
  }

  public Long incrby(String key, long value) {
    try {
      return redisTemplate.opsForValue().increment(key, value);
    } catch (Exception e) {
      log.error("redis incrby error e={}", e.getMessage());
      return null;
    }
  }

  public Object get(String key) {
    try {
      return redisTemplate.opsForValue().get(key);
    } catch (Exception e) {
      log.error("redis get error e = {}", e.getMessage());
      return null;
    }
  }

  public void mSet(Map<String, Object> map) {
    try {
      redisTemplate.opsForValue().multiSet(map);
    } catch (Exception e) {
      log.error("redis mset error e = {}", e.getMessage());
    }
  }

  public List<Object> mGet(List<String> keys) {
    try {
      return redisTemplate.opsForValue().multiGet(keys);
    } catch (Exception e) {
      log.error("redis mGet error e = {}", e.getMessage());
      return null;
    }
  }

  /**
   * <p>todo redis list oprators</p>
   *  @param: key
   *  @param: object
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 17:43
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void lpush(String key, Object object) {
    try {
      redisTemplate.opsForList().leftPush(key, object);
    } catch (Exception e) {
      log.error("redis leftPush error e = {}", e.getMessage());
    }
  }

  public void rpush(String key, Object object) {
    try {
      redisTemplate.opsForList().rightPush(key, object);
    } catch (Exception e) {
      log.error("redis rightPush error e = {}", e.getMessage());
    }
  }

  public void leftPushAll(String key, List<Object> list) {
    try {
      redisTemplate.opsForList().leftPushAll(key, list);
    } catch (Exception e) {
      log.error("redis leftPushAll error e = {}", e.getMessage());
    }
  }

  public void rightPushAll(String key, List<Object> list) {
    try {
      redisTemplate.opsForList().rightPushAll(key, list);
    } catch (Exception e) {
      log.error("redis rightPushAll error e = {}", e.getMessage());
    }
  }

  public List<Object> lRange(String key, Long start, Long end) {
    try {
      return redisTemplate.opsForList().range(key, start, end);
    } catch (Exception e) {
      log.error("redis listrange error e = {}", e.getMessage());
      return null;
    }
  }

  public Object lIndex(String key, Long index) {
    try {
      return redisTemplate.opsForList().index(key, index);
    } catch (Exception e) {
      log.error("redis listIndex error e = {}", e.getMessage());
      return null;
    }
  }

  public Long listSize(String key) {
    try {
      return redisTemplate.opsForList().size(key);
    } catch (Exception e) {
      log.error("redis listSize error e = {}", e.getMessage());
      return null;
    }
  }

  public Object leftPop(String key) {
    try {
      return redisTemplate.opsForList().leftPop(key);
    } catch (Exception e) {
      log.error("redis leftpop error e = {}", e.getMessage());
      return null;
    }
  }

  public Object rightPop(String key) {
    try {
      return redisTemplate.opsForList().rightPop(key);
    } catch (Exception e) {
      log.error("redis leftpop error e = {}", e.getMessage());
      return null;
    }
  }

  /**
   * <p>todo redis hash oprators</p>
   *  @param: key
   *  @param: hashKey
   *  @param: value
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 17:58
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void hSet(String key, String hashKey, Object value) {
    try {
      redisTemplate.opsForHash().put(key, hashKey, value);
    } catch (Exception e) {
      log.error("redis hset error e = {}", e.getMessage());
    }
  }

  public Object hGet(String key, String hashKey) {
    try {
      return redisTemplate.opsForHash().get(key, hashKey);
    } catch (Exception e) {
      log.error("redis hget error e = {}", e.getMessage());
      return null;
    }
  }

  public void hSetAll(String key, Map<String, Object> map) {
    try {
      redisTemplate.opsForHash().putAll(key, map);
    } catch (Exception e) {
      log.error("redis hget error e = {}", e.getMessage());
    }
  }

  public List<Object> hGetAll(String key, List<Object> list) {
    try {
      return redisTemplate.opsForHash().multiGet(key, list);
    } catch (Exception e) {
      log.error("redis hGetAll error e = {}", e.getMessage());
      return null;
    }
  }

  public Long hSize(String key) {
    try {
      return redisTemplate.opsForHash().size(key);
    } catch (Exception e) {
      log.error("redis hSize error e = {}", e.getMessage());
      return null;
    }
  }

  public void hIncrby(String key, String hashKey, long number) {
    try {
      redisTemplate.opsForHash().increment(key, hashKey, number);
    } catch (Exception e) {
      log.error("redis hIncrby error e = {}", e.getMessage());
    }
  }

  public void hIncrbyDouble(String key, String hashKey, double number) {
    try {
      redisTemplate.opsForHash().increment(key, hashKey, number);
    } catch (Exception e) {
      log.error("redis hSize error e = {}", e.getMessage());
    }
  }

  public void hSetNx(String key, String hashKey, Object value) {
    try {
      redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    } catch (Exception e) {
      log.error("redis hSetNx error e = {}", e.getMessage());
    }
  }

  /**
   * <p>todo redis Set operators</p>
   *  @param: key
   *  @param: object
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 19:41
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */
  public void addSetMember(String key, Object member) {
    try {
      redisTemplate.opsForSet().add(key, member);
    } catch (Exception e) {
      log.error("redis Sset error e = {}", e.getMessage());
    }
  }

  public void delSetMember(String key, Object member) {
    try {
      redisTemplate.opsForSet().remove(key, member);
    } catch (Exception e) {
      log.error("redis delmember error e = {}", e.getMessage());
    }
  }

  public Set<Object> setDiff(String key, String otherKey) {
    try {
      return redisTemplate.opsForSet().difference(key, otherKey);
    } catch (Exception e) {
      log.error("redis setDiff error e = {}", e.getMessage());
      return null;
    }
  }

  public Set<Object> setUnion(String key, String otherKey) {
    try {
      return redisTemplate.opsForSet().union(key, otherKey);
    } catch (Exception e) {
      log.error("redis setUnion error e = {}", e.getMessage());
      return null;
    }
  }

  public Set<Object> setInter(String key, String otherKey) {
    try {
      return redisTemplate.opsForSet().intersect(key, otherKey);
    } catch (Exception e) {
      log.error("redis setInter error e = {}", e.getMessage());
      return null;
    }
  }

  public Set<Object> setIntersect(String key, String otherKey) {
    try {
      return redisTemplate.opsForSet().intersect(key, otherKey);

    } catch (Exception e) {
      log.error("redis setIntersect error e = {}", e.getMessage());
      return null;
    }
  }

  /**
   * <p>todo redis zset oprators</p>
   *  @param: key
   *  @param: object
   *  @param: score
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 20:02
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void zSet(String key, Object object, double score) {
    try {
      redisTemplate.opsForZSet().add(key, object, score);
    } catch (Exception e) {
      log.error("redis zSet error e = {}", e.getMessage());
    }
  }

  public Set<Object> zSetRangeByScore(String key, double minScore, double maxScore) {
    try {
      return redisTemplate.opsForZSet().rangeByScore(key, minScore, maxScore);
    } catch (Exception e) {
      log.error("redis zSetRangeByScore error e = {}", e.getMessage());
      return null;
    }
  }

  public Long zSetCount(String key, double minScore, double maxScore) {
    try {
      return redisTemplate.opsForZSet().count(key, minScore, maxScore);
    } catch (Exception e) {
      log.error("redis zSetCount error e = {}", e.getMessage());
      return null;
    }
  }


  /**
   * <p>todo redis hyperLogLog operators</p>
   *  @param: key
   *  @param: object
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 20:46
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void hyperLogLogAdd(String key, Object... object) {
    try {
      redisTemplate.opsForHyperLogLog().add(key, object);
    } catch (Exception e) {
      log.error("redis hyperLogLogAdd error e = {}", e.getMessage());
    }
  }

  public void hyperLogLogSize(String... key) {
    try {
      redisTemplate.opsForHyperLogLog().size(key);
    } catch (Exception e) {
      log.error("redis hyperLogLogSize error e = {}", e.getMessage());
    }
  }

  /**
   * <p>todo redis geo oprators</p>
   *  @param: key
   *  @param: map
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 20:55
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void setGeo(String key, Map<Object, Point> map) {
    try {
      redisTemplate.opsForGeo().add(key, map);
    } catch (Exception e) {
      log.error("redis geo error e = {}", e.getMessage());
    }
  }

  public List<Point> getGeo(String key, String areaName) {
    try {
      return redisTemplate.opsForGeo().position(key, areaName);
    } catch (Exception e) {
      log.error("redis geo error e = {}", e.getMessage());
      return null;
    }
  }

  public String hash(String key, String member) {
    try {
      //geohash算法生成的base32编码值
      List<String> list = redisTemplate.opsForGeo().hash(key, member);
      return list.get(0);
    } catch (Exception e) {
      log.error("redis geo base64 error e = {}", e.getMessage());
      return null;
    }
  }

  public Distance distance(String key, String member1, String member2) {
    try {
      //获取两个给定位置之间的距离
      return redisTemplate.opsForGeo().distance(key, member1, member2,
          RedisGeoCommands.DistanceUnit.KILOMETERS);

    } catch (Exception e) {
      log.error("redis geo distance error e = {}", e.getMessage());
      return null;
    }
  }

  public GeoResults radiusByxy(String key, Point point) {
    try {
      //通过经度，纬度查找附近的,北京王府井位置116.418017,39.914402
      Circle circle = new Circle(point.getX(), point.getY(), Metrics.KILOMETERS.getMultiplier());
      // 返回50条
      RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortDescending().limit(50);
      return redisTemplate.opsForGeo().radius(key, circle, args);
    } catch (Exception e) {
      log.error("redis geo radiusByxy error e = {}", e.getMessage());
      return null;
    }
  }


  /**
   * <p>todo redis delete key oprators</p>
   *  @param: bigListKey
   * @return: void
   * @author: cuizx910872@163.com
   * @date: 2024 10:58
   * @version: 1.0.1
   * Modification History:
   * Date Author Version Description
   * -----------------------------------------------------------
   * 2024 cuizx v1.0.1 init
   */

  public void del(String key) {
    try {
      redisTemplate.unlink(key);
    } catch (Exception e) {
      log.error("del error e = {} ", e.getMessage());
    }

  }

  public void delBigList(String bigListKey) {
    try {
      Long size = redisTemplate.opsForList().size(bigListKey);
      if (size != null && !size.equals(0L)) {
        int counter = 0;
        int left = 100;
        while (counter < size) {
          redisTemplate.opsForList().trim(bigListKey, counter, left);
          counter += left;
        }
      }

    } catch (Exception e) {
      log.error("delBigList error e = {} ", e.getMessage());
    }

  }


  public void delBigHash(String bigHashKey) {
    try (Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(bigHashKey, ScanOptions.scanOptions().count(100).build())) {
      while (cursor.hasNext()) {
        String hkey = (String) cursor.next().getKey();
        Long delete = redisTemplate.opsForHash().delete(bigHashKey, hkey);
      }
    } catch (Exception e) {
      log.error("delBigHash error e = {} ", e.getMessage());
    }
  }

  public void delBigSet(String bigSetKey) {
    try (Cursor<Object> cursor = redisTemplate.opsForSet().scan(bigSetKey, ScanOptions.scanOptions().count(100).build())) {
      while (cursor.hasNext()) {
        Object value = cursor.next();
        Long delete = redisTemplate.opsForSet().remove(bigSetKey, value);
      }
    } catch (Exception e) {
      log.error("delBigSet error e = {} ", e.getMessage());
    }
  }

  public void delBigZset(String bigZsetKey) {
    try (Cursor<ZSetOperations.TypedTuple<Object>> cursor = redisTemplate.opsForZSet().scan(bigZsetKey, ScanOptions.scanOptions().count(100).build())) {
      while (cursor.hasNext()) {
        ZSetOperations.TypedTuple<Object> objectTypedTuple = cursor.next();
        Long delete = redisTemplate.opsForZSet().remove(bigZsetKey, objectTypedTuple);
      }
    } catch (Exception e) {
      log.error("delBigZset error e = {} ", e.getMessage());
    }
  }
}

